function gewCSMMaterial(effect,name)
{ 
  // general properties
  gewMaterial.call(this,effect,name);
  this.type = GEW_SHADOW_MESH;
  
  // AlphaRef properties
  this.texture = null;
  this.alphaRef = 0.0;
  this.modeMatBuf = new WebGLFloatArray(16* GEW_MAX_OBJ_VCB);
}
//gewCSMMaterial.prototype = new gewMaterial();
extend2(gewCSMMaterial,gewMaterial);
gewCSMMaterial.prototype.render = function()
{
  // Render node list
  var effect = this.effect;
  var currPass = effect.currentPass;
  if(currPass!= this.type)
    return;
  var gl = this.gl;  
  var shader;
  switch(this.type)
  {
    case GEW_SHADOW_MESH:
      shader = effect.shaders.mesh;
      break;
    case GEW_SHADOW_ALPHA_REF:
      shader = effect.shaders.alphaRef;
      if(!this.texture|| !this.texture.isReady)
        return;
      gl.uniform1i(shader.texture, 0);
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, this.texture.glName);
      gl.uniform1f(shader.alphaRef, this.alphaRef);
      break;
    case GEW_SHADOW_SKINNED_MESH:
      shader = effect.shaders.skinnedMesh;
      break;
  }
  this.isRendering = true;
  var scene3d = effect.scene3d;
  var list  = this.nodeList;
  var listLen = list.length;
  var previousMesh = null;
  var view_pos = scene3d.viewPosition;
  var max_distance_square = effect.maxDistanceSquare;
  if (this.batchType == GEW_NO_BATCH || this.type== GEW_SHADOW_SKINNED_MESH) {
    // Bind default obj idx buffer
    var game = effect.game;
    if (this.type != GEW_SHADOW_SKINNED_MESH) {
      gl.bindBuffer(gl.ARRAY_BUFFER, game.defaultObjIdxGLBuffer);
      gl.vertexAttribPointer(shader.inObjIdx, 1, gl.FLOAT, false, 0, 0);
    }
    for (var i = 0; i < listLen; i++) {
      var node = list[i];
      if (!node.getFlag(NODE_FRUSTUM_IN) || !node.isVisible)
          continue;
      if(effect.mode==1){
        var distance_square = node.position.sub(view_pos,gewRegVec0).getLengthSquare();
        if(distance_square>max_distance_square)
          continue;
      }
      gl.uniformMatrix4fv(shader.modelMat, false, node.modelMat.data);
      if (previousMesh != node.mesh) {
        node.setAttributePointers(this);
        previousMesh = node.mesh;
      }
      node.render(this);
    }
  }
  else if( this.batchType == GEW_VERTEX_CONSTANTS_BATCH)
  {
    var batchs = {};
    // Find the batchs
    for (var i = 0; i < listLen; i++) 
    {
      var node = list[i];
      if(!node.getFlag(NODE_FRUSTUM_IN)||!node.isVisible)
        continue;
      if(effect.mode==1){
        var distance_square = node.position.sub(view_pos,gewRegVec0).getLengthSquare();
        if(distance_square>max_distance_square)
          continue;
      }
      var mesh_name = node.mesh.name;
      if(!batchs[mesh_name])
      {
        var batch = batchs[mesh_name] = {};
        batch.mesh = node.mesh;
        batch.nodeList = [];          
      }
      else
        var batch = batchs[mesh_name];
      batch.nodeList.push(node);
    }
    // Draw all batchs
    for(var i in batchs)
    {
      var batch = batchs[i];
      var m = batch.mesh;
      
      if(!m.isReadyForBatch)
        m.makeVBOForBatch(gl);
              
      // Set atrribute poitters
      gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.positions);
      gl.vertexAttribPointer(shader.inPosition, 3, gl.FLOAT, false, 0, 0);
      gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.objIdx);
      gl.vertexAttribPointer(shader.inObjIdx, 1, gl.FLOAT, false, 0, 0);
      if(this.type ==GEW_SHADOW_ALPHA_REF){
        gl.bindBuffer(gl.ARRAY_BUFFER, m.batchGLBuffers.texcoords);
        gl.vertexAttribPointer(shader.inTexCoord0, 2, gl.FLOAT, false, 0, 0);
      }      
      // Get model mat & render
      var batchNodeList = batch.nodeList;
      var batchNodeNum = batchNodeList.length;
      var offset = 0;
      var max_obj = m.maxObjPerBatch;
      var method = m.renderType;
      for(var n=0;n<batchNodeNum;n++)
      {
        this.modeMatBuf.set( batchNodeList[n].modelMat.data, 16*offset);
        offset++;
        if(offset== max_obj || n==(batchNodeNum-1) )
        {
          // render
          gl.uniformMatrix4fv(shader.modelMat , false, this.modeMatBuf);
          if (method == GEW_TRIANGLES_NON_INDICES) 
          {
            var ver_num = (m.vertices.length / 3)*offset ;
            gl.drawArrays(gl.TRIANGLES, 0, ver_num);
          }
          else if(method== GEW_TRIANGLES_INDICES)
          {
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, m.batchGLBuffers.indices);
            var indicesNum = m.indices[0].length*offset;
            gl.drawElements(gl.TRIANGLES,indicesNum,gl.UNSIGNED_SHORT,0);
          }
          offset = 0;
        }
      }                
    }
  }  
  this.isRendering = false;
}
